package com.estock.platform.http.client;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.log4j.Logger;

import com.estock.platform.http.request.StockClientRequest;
import com.estock.platform.http.response.DownloadResponse;
import com.estock.platform.http.response.JSONResponse;

public abstract class URLDownloadClient extends AbstractURLConnectClient {
	
	private static Logger logger = Logger.getLogger(URLDownloadClient.class);
	
	private static final int BUFFER_SIZE = 1024;
	
	// static variables belong to all threads.
	private static AtomicInteger connectedCount = new AtomicInteger(0);
	private static AtomicInteger completedCount = new AtomicInteger(0);
	private static AtomicInteger errorNum = new AtomicInteger(0);
	
	@SuppressWarnings("unchecked")
	@Override
	public <T extends JSONResponse> T execute(StockClientRequest request,
			Map<String, String> headers, String requestMethod,
			Class<T> responseClass) {
		String downloadDir = getDownloadDirectory();
		try {
			saveToFile(request.getLocationUri(), downloadDir);
		} catch (Exception e) {
			System.out.println("Error in reading data from connection in processing file: " + downloadDir + ". error num: " + errorNum.incrementAndGet());
		}
		
		DownloadResponse response = null;
		try {
			response = (DownloadResponse) responseClass.newInstance();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
		response.setFileName(downloadDir);
		return (T) response;
	}
	
	protected abstract String getDownloadDirectory();
 
    public void saveToFile(String destUrl, String fileName) throws Exception {
		FileOutputStream outputStream = null;
		BufferedInputStream inputStream = null;
		byte[] buffer = new byte[BUFFER_SIZE];
		int size = 0;
		
			// HttpURLConnection can not meet my requirement, it cannot afford so many requests.
			/*
			URL url = new URL(destUrl);;
			URLConnection conn = url.openConnection();
			HttpURLConnection httpUrl = null;
			if (conn instanceof HttpURLConnection) {
				httpUrl = (HttpURLConnection) conn;
				httpUrl.setRequestMethod(RequestUtils.HttpMethod.GET);
				httpUrl.setConnectTimeout(600000);
				httpUrl.setRequestProperty("connection", "Keep-Alive");
				httpUrl.connect();
				connectedCount.incrementAndGet();
			}
			inputStream = new BufferedInputStream(httpUrl.getInputStream());
			*/
			
			// HttpClient also cannot afford so many requests.
		    /* 
			HttpClientObject hco = new HttpClientObject();
			hco.setGet(destUrl);
			hco.submit();
			String responseContent = hco.getResponseString();
			inputStream = new BufferedInputStream(new ByteArrayInputStream(responseContent.getBytes()));
			*/
			
			// No doubt cannot afford so many requests, but since it has no noising error trace, keep it.
			CloseableHttpClient httpclient = HttpClients.createDefault();
	        try {
	            HttpGet httpget = new HttpGet(destUrl);
	            CloseableHttpResponse response = httpclient.execute(httpget);
	            try {
	                // Get hold of the response entity
	                HttpEntity entity = response.getEntity();

	                // If the response does not enclose an entity, there is no need
	                // to bother about connection release
	                if (entity != null) {
	                	inputStream = new BufferedInputStream(entity.getContent());
	                    try {
//	                    	inputStream.read();
	                        // do something useful with the response
	                        
	            			File file = new File(fileName);
	            			if (!file.exists()) {
	            				if (!file.getParentFile().exists()) {
	            					file.getParentFile().mkdirs();
	            				}
	            				file.createNewFile();
	            			}
	            			outputStream = new FileOutputStream(fileName);
	            			
	            			connectedCount.incrementAndGet();

	            			while ((size = inputStream.read(buffer)) != -1)
	            				outputStream.write(buffer, 0, size);
	            			
	            			completedCount.incrementAndGet();
	            			
	            			logger.info("Write yahoo stock data to file: " + fileName + ", connected " + connectedCount + ", completed " + completedCount);
	            			System.out.println("Write yahoo stock data to file: " + fileName + ", connected " + connectedCount + ", completed " + completedCount);
	                    } catch (IOException ex) {
	                        // In case of an IOException the connection will be released
	                        // back to the connection manager automatically
	                        throw ex;
	                    } finally {
	                        // Closing the input stream will trigger connection release
	                    	inputStream.close();
	                    }
	                }
	            } finally {
	                response.close();
	            }
	        } finally {
	            httpclient.close();
	        }

	}
    
}
